package com.qianfeng.log.web.service.impl;

//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼                  BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  
//  


import com.qianfeng.log.web.event.SaveLogToCacheEvent;
import com.qianfeng.log.web.event.SaveLogToEsEvent;
import com.qianfeng.log.web.exception.MyBaseException;
import com.qianfeng.log.web.feign.CacheService;
import com.qianfeng.log.web.feign.LogServiceFeign;
import com.qianfeng.log.web.feign.SearchServiceFeign;
import com.qianfeng.log.web.pojo.SysOperLog;
import com.qianfeng.log.web.service.LogWebService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Map;

/**
 * Created by Jackiechan on 2022/2/7/15:00
 *
 * @author Jackiechan
 * @version 1.0
 * @since 1.0
 */
@Service
public class LogWebServiceImpl implements LogWebService {

    private LogServiceFeign logServiceFeign;

    private CacheService cacheService;

    private SearchServiceFeign searchServiceFeign;

    private ApplicationContext context;


    @Autowired
    public void setSearchServiceFeign(SearchServiceFeign searchServiceFeign) {
        this.searchServiceFeign = searchServiceFeign;
    }

    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    @Autowired
    public void setCacheService(CacheService cacheService) {
        this.cacheService = cacheService;
    }

    @Autowired
    public void setLogServiceFeign(LogServiceFeign logServiceFeign) {
        this.logServiceFeign = logServiceFeign;
    }

    @Override
    public SysOperLog findById(Long id) {
        //我们需要通过查询另外一个程序来获取数据
        Assert.isTrue(id>0,()->{
            throw new MyBaseException("主键格式不对", -100);
        });
        //先查询缓存
        SysOperLog operLog = cacheService.hGetAll(id);
        System.err.println("从缓存中查询到的结果"+operLog);
        if (operLog == null||operLog.getOperId()==null) { //还要判断一下数据在不在数据库,我们可以在缓存中保存一下主键的最大值
            System.err.println("没有数据");
            //查询缓存中的主键的最大值,然后和当前传递的主键进行比较,如果传递的主键大于当前最大值,意味着查询的数据是不存在的,我们就不查询数据库
            Long maxId = cacheService.getMax("operid");//获取到保存的最大的主键
            if (id <= maxId) {//只有查询的数据在主键范围内我们才查询数据库
                System.err.println("查询数据库");
                //否则就可以查询数据库
                //缓存中没有,做一个防穿透的判断,从数据库中查询
                operLog = logServiceFeign.findById(id);//请求后面的服务,获取数据,后面的服务查询的是数据库
                //放入到缓存中一份
                if (operLog != null) {
                    //我们测试发现,如果存放到缓存中卡主或者出现问题,会导致查询的数据不能返回
                    //但是其实数据我们查询到了,应该可以返回给客户端
                    //也就是存放到缓存严格来说不是主要的业务,是辅助业务,所以可以和保存数据不在一个线程中
                    //可以通过异步的事件在事件内部保存到缓存中
                    //在这里单独开一个线程去保存
//                    SysOperLog finalOperLog = operLog;
//                    CompletableFuture.runAsync(()->{//发起一个异步操作
//                        try {
//                            Thread.sleep(5000);
//                        } catch (InterruptedException e) {
//                            e.printStackTrace();
//                        }
//                        cacheService.hPut(id, finalOperLog);
//                    });
                    context.publishEvent(new SaveLogToCacheEvent(operLog));//发送一个事件
                }
            }

        }

        return operLog;
    }

    @Override
    public void addLog(SysOperLog log) {
        //用户传递的数据是没有主键的,而后面要求的是有主键的,在这里先设置主键
        //主键是从redis中获取过来的
        Long operid = cacheService.incr("operid");
        log.setOperId(operid);
        logServiceFeign.addLog(log);
        //这里就应该把数据添加到es中,怎么添加进去?
        //添加到es和添加数据两个相比较,es属于辅助业务,通过异步执行,我们直接通过mq把数据传递到mq,es那边接受消息就行了
        context.publishEvent(new SaveLogToEsEvent(log));
    }

    @Override
    public List<Map> searchByTitile(String title) {
        return searchServiceFeign.searchByTitle(title);
    }

}
